/**
 * 自定义 request 网络请求工具,基于axios
 * @author LiQingSong
 */
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios'
import { notification, message } from 'antd'
import settings from '@/config/settings'
import { getToken, removeToken } from '@/utils/localToken'
import { PromiseData } from '@/@types/request'

export interface ResponseData<T = unknown> {
  code: number
  data?: T
  msg?: string
}

// 操作返回信息
export interface OperateData {
  message: string
  success: number
}

const jumpUrl = ['/platform/dict/selectAllDict', '/platform/province/selectTree', '/platformReport/getHomeInfo']

const customCodeMessage: { [key: number]: string } = {
  401: '当前用户登入信息已失效，请重新登入再操作', // 未登陆
}

const serverCodeMessage: { [key: number]: string } = {
  200: '服务器成功返回请求的数据',
  400: 'Bad Request',
  401: 'Unauthorized',
  403: 'Forbidden',
  404: 'Not Found',
  500: '服务器发生错误，请检查服务器(Internal Server Error)',
  502: '网关错误(Bad Gateway)',
  503: '服务不可用，服务器暂时过载或维护(Service Unavailable)',
  504: '网关超时(Gateway Timeout)',
}

/**
 * 异常处理程序
 */
const errorHandler = (error: any) => {
  const { response, notifi } = error
  if (notifi === 'CustomError') {
    // 自定义错误
    const { config, data } = response
    const { url, baseURL } = config
    const { code, msg } = data
    const reqUrl = url.split('?')[0].replace(baseURL, '')
    const noVerifyBool = settings.ajaxResponseNoVerifyUrl.includes(reqUrl)
    if (!noVerifyBool) {
      notification.error({
        message: '提示',
        description: customCodeMessage[code] || msg || 'Error',
      })

      if (code === 401) {
        setTimeout(() => {
          window.location.href = '/user/login'
        }, 500)
      }
    }
  } else if (notifi === 'CancelToken') {
    // 取消请求 Token
    // eslint-disable-next-line no-console
    console.log(notifi)
  } else if (response && response.status) {
    const errorText = serverCodeMessage[response.status] || response.statusText
    const { status, request } = response
    notification.error({
      message: `请求错误 ${status}: ${request.responseURL}`,
      description: errorText,
    })
  } else if (!response) {
    notification.error({
      description: '您的网络发生异常，无法连接服务器',
      message: '网络异常',
    })
  }

  return Promise.reject(error)
}

// 创建一个变量来表示是否已经弹出了错误提示 -- 401特殊处理
let isErrorMessageDisplayed = false

/**
 * 配置request请求时的默认参数
 */
const service = axios.create({
  baseURL: import.meta.env.VITE_APP_APIHOST || '', // url = api url + request url
  withCredentials: false, // 当跨域请求时发送cookie
  timeout: 0, // 请求超时时间,5000(单位毫秒) / 0 不做限制
})

/**
 * 请求前
 * 请求拦截器
 */
service.interceptors.request.use(
  (config: AxiosRequestConfig) => {
    // 从local中获取token
    const TOKEN = getToken()
    const { headers, url } = config

    if (TOKEN && headers && !jumpUrl.includes(url!.split('?')[0])) {
      headers[settings.ajaxHeadersTokenKey] = TOKEN
    }

    return config
  },

  (error) => errorHandler(error),
)

/**
 * 请求后
 * 响应拦截器
 */
service.interceptors.response.use(
  (response: AxiosResponse<PromiseData>) => {
    // 判断接口是否成功
    const res = response.data
    // console.log('res🚀🚀🚀🚀', res)
    // TODO 根据接口规范通过success来判断接口请求是否成功
    if (res.code === 200) {
      // 接口正常直接返回
      return res
    }
    if (res.code === 401) {
      if (!isErrorMessageDisplayed) {
        message.error('登录已过期，请重新登录')
        // 登录信息过期
        removeToken()
        setTimeout(() => {
          window.location.href = '/user/login'
        }, 500)
        isErrorMessageDisplayed = true
      }
    }
    if (res.code === 404) {
      // 暂定服务出问题处理
      message.error('服务出错啦')
      // return res
      return Promise.reject(res)
    }
    if (res && !res.code) {
      // 特殊处理获取图片文件流
      return res
    }
    if (res.code === 500 || res.code === 501 || res.code === 502 || res.code === 503 || res.code === 504) {
      message.error(res.msg || '服务出错啦，请联系开发人员')
      // return res
      return Promise.reject(res)
    }
    return res
  },
  (error) => errorHandler(error),
)

interface HttpRequest {
  getUri(config?: AxiosRequestConfig): string
  get<T = PromiseData>(url: string, config?: AxiosRequestConfig): Promise<T>
  delete<T = PromiseData>(url: string, config?: AxiosRequestConfig): Promise<T>
  post<T = PromiseData>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>
  put<T = PromiseData>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>
  patch<T = PromiseData>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>
}

// 为了类型安全二次封装
const request: HttpRequest = {
  getUri: (config?: AxiosRequestConfig) => service.getUri(config),
  get: (url: string, config?: AxiosRequestConfig) => service.get(url, config),
  delete: (url: string, config?: AxiosRequestConfig) => service.delete(url, config),

  post: (url: string, data?: any, config?: AxiosRequestConfig) => service.post(url, data, config),

  put: (url: string, data?: any, config?: AxiosRequestConfig) => service.put(url, data, config),

  patch: (url: string, data?: any, config?: AxiosRequestConfig) => service.patch(url, data, config),
}
export default request
